#pragma once
#include <cstddef>
#include <iterator>
#include <stdexcept>
#include <type_traits>
#include <utility>

namespace lcir {
/// TODO: 目前所有range都不支持作为const传参
/// 这个文件提供给range-loop一组通用api简化操作

/// 迭代器的适配器
/// 默认情况需要迭代器自身提供pointer和reference类型
template <class IteratorT> class TraitAdaptor {
public:
  using pointer = typename IteratorT::pointer;
  using reference = typename IteratorT::reference;
};

template <class WrapperedIteratorT> class IndexIterator {
  using pointer = typename TraitAdaptor<WrapperedIteratorT>::pointer;
  using reference = typename TraitAdaptor<WrapperedIteratorT>::reference;
  using indexPair = std::pair<size_t, reference>;
  size_t index{0};
  WrapperedIteratorT it;

public:
  IndexIterator(const WrapperedIteratorT &it) : it(it) {}
  friend bool operator==(const IndexIterator &lhs, const IndexIterator &rhs) {
    return lhs.it.operator->() == rhs.it.operator->();
  }

  friend bool operator!=(const IndexIterator &lhs, const IndexIterator &rhs) {
    return lhs.it.operator->() != rhs.it.operator->();
  }
  IndexIterator &operator++() {
    it++;
    index++;
    return *this;
  }
  IndexIterator &operator++(int) {
    auto temp = *this;
    it++;
    index++;
    return temp;
  }
  pointer operator->() const { return it.operator->(); }
  indexPair operator*() const { return {index, *it}; }
};

template <class WrapperedIteratorT> class IncIterator {
  using pointer = typename TraitAdaptor<WrapperedIteratorT>::pointer;
  using reference = typename TraitAdaptor<WrapperedIteratorT>::reference;
  using indexPair = std::pair<size_t, reference>;
  WrapperedIteratorT it;
  bool haveIncreased{false};

public:
  IncIterator(const WrapperedIteratorT &it) : it(it) {}
  friend bool operator==(const IncIterator &lhs, const IncIterator &rhs) {
    return lhs.it.operator->() == rhs.it.operator->();
  }

  friend bool operator!=(const IncIterator &lhs, const IncIterator &rhs) {
    return lhs.it.operator->() != rhs.it.operator->();
  }
  IncIterator &operator++() {
    [[unlikely]] if (!haveIncreased)
      throw std::runtime_error("inc iterator increament  before dereferenced");
    haveIncreased = false;
    return *this;
  }
  IncIterator &operator++(int) {
    [[unlikely]] if (!haveIncreased)
      throw std::runtime_error("inc iterator increament  before dereferenced");
    haveIncreased = false;
    return *this;
  }
  reference operator*() {
    [[unlikely]] if (haveIncreased)
      throw std::runtime_error("inc iterator can'not dereferenced twice");
    haveIncreased = true;
    auto tempIt = it;
    it++;
    return *tempIt;
  }
};
template <class RangeType, bool IsConstant> struct RangeTrait;
template <class T> struct RangeTrait<T, true> {
  using RangeType = const T&;
};
template <class T> struct RangeTrait<T, false> {
  using RangeType = T&;
};
template <class T, bool IsConstant> class RangeBase ;
template <class T> class RangeBase<T, false> {
protected: 
  using RangeType = typename RangeTrait<T, false>::RangeType;
  RangeType range;
public:
  using type = RangeType;
  RangeBase(T &range) : range(range) {}
};
template <class T> class RangeBase<T, true> {
protected: 
  using RangeType = typename RangeTrait<T, true>::RangeType;
  const RangeType range;
public:
  using type = RangeType;
  RangeBase(T &&range) : range(range) {}
};

// 普通的Range
template <class RangeType> class Range {
public:
  using type = RangeType;
  RangeType &range;
  explicit Range(RangeType &range) : range(range) {}
  auto begin() { return range.begin(); }
  auto end() { return range.end(); }
  auto begin() const { return range.begin(); }
  auto end() const { return range.end(); }
};

/// 逆序遍历容器
template <class RangeType> class ReverseRange {
public:
  using type = RangeType;
  RangeType &range;
  explicit ReverseRange(RangeType &range) : range(range) {}
  auto begin() { return range.rbegin(); }
  auto end() { return range.rend(); }
  auto begin() const { return range.rbegin(); }
  auto end() const { return range.rend(); }
};

/// 遍历容器，解引用能得到下标
template <class RangeType> class IndexRange {
public:
  using type = RangeType;
  RangeType &range;
  explicit IndexRange(RangeType &range) : range(range) {}
  auto begin() { return IndexIterator(range.begin()); }
  auto end() { return IndexIterator(range.end()); }
  auto begin() const { return IndexIterator(range.begin()); }
  auto end() const { return IndexIterator(range.end()); }
};

/// 这个东西在解引用后自动递增，用来处理遍历链表时修改节点导致迭代器失效的问题
template <class RangeType> class IncRange {
public:
  using type = RangeType;
  RangeType &range;
  explicit IncRange(RangeType &range) : range(range) {}
  auto begin() { return IncIterator(range.begin()); }
  auto end() { return IncIterator(range.end()); }
  auto begin() const { return IncIterator(range.begin()); }
  auto end() const { return IncIterator(range.end()); }
};

/// 把range组合到一起，有点像装饰器，但好像会有一定问题（比如incrange叠incrange）
/// TODO: 这玩意先不搞了
template<class ...RangeTypes>
struct RangeCombiner {
  auto operator() () {

    
  }
};
}; // namespace lcir